using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Drawing;

namespace Athena.Core
{
    [Serializable()]
    public class Compartment : Container
    {
        public static int COUNT = 0;
        public double Volume = 1;
        /// <summary>
        /// makes a clone of this module
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Compartment(this);
        }

        /// <summary>
        /// Add an item into the Container. If the item is a module, all the nodes and reactions in that
        /// module are added
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public override bool AddItem(Item item)
        {
            if (_Items == null) _Items = new Hashtable();

            if (item == null || item == this || item is GlobalSpecies) return true;

            if (_Items.ContainsValue(item))
            {
                if (item.Parent != this) item.Parent = this;
                return true;
            }

            if (_Items.ContainsKey(item.ID)) item.ID = RequestNewID(item.ID);

            if (!ValidID(item.ID)) return false;

            _Items[item.ID] = item;

            if (item.Parent != this) item.Parent = this;
            
            return true;
        }

        public override void GenerateDrawable(System.Drawing.PointF point)
        {
            Objects.CompartmentGlyph glyph = new Objects.CompartmentGlyph(point);
            glyph.Item = this;

            List<Node> nodes = LocalNodes;
            List<Edge> edges = LocalReactions;

            int max = nodes.Count * 30;
            Random rand = new Random();

            foreach (Item i in nodes)
            {
                if (i.Drawable == null) i.GenerateDrawable(new PointF(glyph.Location.X + rand.Next(max), glyph.Location.Y + rand.Next(max)));
            }
            foreach (Item i in edges)
            {
                if (i.Drawable == null) i.GenerateDrawable(new PointF(glyph.Location.X + rand.Next(max), glyph.Location.Y + rand.Next(max)));
            }

            _Drawable = glyph;

            ((Objects.CompartmentGlyph)_Drawable).GenerateDrawablesFromItem();

        }
        /*
        /// <summary>
        /// returns all the items that are contained in this Container
        /// This function also gets the items inside containers within this container
        /// </summary>
        /// <returns></returns>
        public override Hashtable AllItems
        {
            get
            {
                Hashtable items = new Hashtable();
                Hashtable parentIDs = new Hashtable();

                if (_Items != null && _Items.Count > 0)
                {
                    foreach (string key in _Items.Keys)
                    {
                        Item i = _Items[key] as Item;
                        if (i != null && i != null)
                        {
                            items[_ID + "_" + key] = i;
                        }
                    }

                    foreach (string key in _Items.Keys)
                    {
                        Item i = _Items[key] as Item;
                        if (i != null && i != null)
                        {
                            if (i is Container)
                            {
                                Hashtable subcomponents = ((Container)i).AllItems;
                                foreach (string s in subcomponents.Keys)
                                {
                                    Object o = subcomponents[s];
                                    if (o is Item)
                                    {
                                        Item n = (Item)o;
                                        if (items.ContainsKey(s))
                                        {
                                            Item n2 = (Item)items[s];  //the item with same name
                                            if (n.Depth >= n2.Depth)
                                            {
                                                Item parent = n.Parent;
                                                if (parent != null)
                                                {
                                                    string s2 = n.ID;
                                                    while (items.ContainsKey(s2))
                                                    {
                                                        s2 = parent.ID + "_" + s2;
                                                        parent = parent.Parent;
                                                        if (parent == null || parent == n.Parent)
                                                            break;
                                                    }
                                                    items[_ID + "_" + s2] = n;
                                                }
                                            }
                                            else
                                            {
                                                items[_ID + "_" + s] = n;
                                                Item parent = n2.Parent;
                                                if (parent != null)
                                                {
                                                    string s2 = n2.ID;
                                                    while (items.ContainsKey(s2))
                                                    {
                                                        s2 = parent.ID + "_" + s2;
                                                        parent = parent.Parent;
                                                        if (parent == null || parent == n2.Parent)
                                                            break;
                                                    }
                                                    items[_ID + "_" + s2] = n2;
                                                }
                                            }
                                            n2 = (Item)items[s];
                                            if (n2.ID == s && n2.Parent != this)
                                            {
                                                Item parent = n2.Parent;
                                                if (parent != null)
                                                {
                                                    string s2 = parent.ID + "_" + n2.ID;
                                                    parent = parent.Parent;
                                                    while (items.ContainsKey(s2))
                                                    {
                                                        s2 = parent.ID + "_" + s2;
                                                        parent = parent.Parent;
                                                        if (parent == null || parent == n2.Parent)
                                                            break;
                                                    }
                                                    items.Remove(s);
                                                    items[_ID + "_" + s2] = n2;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            items[_ID + "_" + s] = n;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                return items;
            }
        }
        */

        /// <summary>
        /// The copy constructor
        /// </summary>
        /// <param name="copy">the module to copy</param>
        public Compartment(Compartment copy)
            : base(copy)
        {
            Volume = copy.Volume;

            ++COUNT;
        }

        /// <summary>
        /// Default constructor
        /// </summary>
        public Compartment()
            : base("compartment", "c" + COUNT)
        {
            Volume = 1;
            ++COUNT;
        }

        /// <summary>
        /// The main constructor
        /// </summary>
        /// <param name="type">type of this module</param>
        /// <param name="id">id</param>
        /// <param name="inputs">number of inputs</param>
        /// <param name="outputs">number of outputs</param>
        /// <param name="items">number of items contained, including inputs and outputs</param>
        public Compartment(string type, string id, int items, double Vol)
            : base(type, id)
        {
            Volume = Vol;
            ++COUNT;
        }

    }
}
